package com.quan.commons.filter;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Sets;
import com.quan.commons.constant.Constant;
import com.quan.commons.context.StopWatchHolder;
import com.quan.commons.context.TraceIdHolder;
import com.quan.commons.utils.TraceIdUtil;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Set;

/**
 * 负责从request的header里取出TraceId放入TraceIdHolder
 * 优先级放在requestContextFilter之后
 * 若需要在filter获取请求参数和返回值可以参考
 * http://slackspace.de/articles/log-request-body-with-spring-boot/
 */
@Slf4j
public class TraceIdContextFilter implements Filter {

    private static final String INIT_PARAMETER_KEY = "exclude-uri";

    private static Set<String> EXCLUDE_URI_SET;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 可以通过配置server.servlet.context-parameters.exclude-uri来覆盖
        String excludeUri = filterConfig.getServletContext().getInitParameter(INIT_PARAMETER_KEY);
        String[] excludeUris;
        if (StrUtil.isNotEmpty(excludeUri)) {
            excludeUris = excludeUri.split(",");
        } else {
            excludeUris = Constant.EXCLUDE_URI;
        }
        EXCLUDE_URI_SET = Sets.newHashSet(excludeUris);
        log.info("[traceIdContextFilter]初始化");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 排除特殊链接
        if (EXCLUDE_URI_SET.contains(((HttpServletRequest) request).getRequestURI())) {
            chain.doFilter(request, response);
            return;
        }

        StopWatchHolder.init();
        TraceIdHolder.init();

        String source = request.getRemoteAddr();
        String target = ((HttpServletRequest) request).getRequestURI();
        StopWatchHolder.setName(target);

        String traceId = TraceIdUtil.generateTraceId();
        TraceIdHolder.resetByTraceId(traceId);
        log.info(":::接口请求开始:::");
        log.info("==>来源地址: {}, 目标地址: {}, 生成traceId: {}",
                source,
                target,
                traceId
        );

        try {
            chain.doFilter(request, response);
        } finally {
            // 入参和返回值在InterfaceLogAop
            log.info("<=={}", StopWatchHolder.prettyPrint());
            log.info(":::接口请求结束:::\r\n");
            TraceIdHolder.remove();
            StopWatchHolder.remove();
        }
    }

    @Override
    public void destroy() {
        if (log.isDebugEnabled()) {
            log.debug("[traceIdContextFilter]销毁");
        }
    }
}
